package com.element.security.server.authorization;

import com.element.security.server.global.granter.ParamAuthenticationProvider;
import com.element.security.server.handler.AuthSuccessHandler;
import com.element.security.server.service.IAuthUserDetailsService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

import javax.annotation.Resource;

/**
 * @auther zhangwj
 * @date 2021/3/11 上午10:25
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Value(value = "${spring.cloud.request.head}")
    private String requestHead;

    private final static String LOGIN_PAGE = "/login/index";

    private final static String LOGIN_PROCESS_URL = "/login";

    private final static String LOGIN_ALL = "/login/**";

    // 允许通过的请求
    private final String[] REQUEST_MATCHERS = {"/oauth/token", "/oauth/code", "/oauth/authorize"};

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * 这一步的配置是必不可少的，否则SpringBoot会自动配置一个AuthenticationManager,覆盖掉内存中的用户
     *
     * @return AuthenticationManager 认证管理对象
     */
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Resource
    private IAuthUserDetailsService authUserDetailsService;

    /**
     * anyRequest() 所有接口
     * authenticated() 需要进行权限认证
     * permitAll() 不需要进行权限认证
     * antMatchers(String) 匹配接口
     * requestMatchers() 允许过滤的路由
     * authorizeRequests() 授权管理控制
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().headers().frameOptions().disable();

        // 必须配置，不然OAuth2的http配置不生效
        http.requestMatchers()
                .antMatchers(REQUEST_MATCHERS)
                .antMatchers(LOGIN_PAGE)
                .antMatchers(LOGIN_PROCESS_URL);
        // 所有接口进行权限认证
        http.authorizeRequests()
                .antMatchers(LOGIN_ALL).permitAll()
                .anyRequest().authenticated();

        http.formLogin()
                .loginPage((requestHead + LOGIN_PAGE))
                .loginProcessingUrl(LOGIN_PROCESS_URL)
                .successHandler(new AuthSuccessHandler(requestHead));

        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);
        // 可以设置踢出用户后续操作
        http.sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(false);
        http.sessionManagement().sessionFixation().none();

        // 添加自定义参数验证
        ParamAuthenticationProvider paramAuthenticationProvider = new ParamAuthenticationProvider(authUserDetailsService);
        http.authenticationProvider(paramAuthenticationProvider);
    }
}
